package com.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.dao.userMapper;
import com.framework.MessageConverter.UserMessageConverter;
import com.github.pagehelper.PageHelper;
import com.messageHandler.PersonMessageHandler;
import com.service.ISayHello;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.apache.activemq.spring.ActiveMQConnectionFactory;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.*;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.listener.DefaultMessageListenerContainer;
import org.springframework.jms.listener.adapter.MessageListenerAdapter;
import org.springframework.jms.remoting.JmsInvokerProxyFactoryBean;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.interceptor.TransactionInterceptor;
import org.springframework.web.client.RestTemplate;
import redis.clients.jedis.JedisPoolConfig;

import javax.sql.DataSource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Properties;

@Configuration
@PropertySource({"classpath:setting.properties", "classpath:jdbc.properties", "classpath:redis.properties"})
//@Import({RmiService.class,JMSService.class,WebValidatorConfig.class})
@EnableTransactionManagement//启用事务管理
@EnableAspectJAutoProxy(proxyTargetClass = true)//启用代理支持
@EnableCaching//启用缓存支持
public class RootConfig implements EnvironmentAware {

    private Environment environment;
    private Logger logger = LoggerFactory.getLogger( RootConfig.class );


    //=============================数据库配置============
    //数据源
    @Profile({"dev","default"})
    @Bean
    public DruidDataSource druidDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName( environment.getProperty( "jdbc.driverClassName", "com.mysql.jdbc.Driver" ) );
        dataSource.setUrl( environment.getProperty( "jdbc.url" ) );
        dataSource.setUsername( environment.getProperty( "jdbc.username" ) );
        dataSource.setPassword( environment.getProperty( "jdbc.password" ) );
        return dataSource;
    }

    //============================sqlSession=================
    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DruidDataSource druidDataSource) {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource( druidDataSource );
        sqlSessionFactoryBean.setTypeAliasesPackage( "com.model" );
        try {
            sqlSessionFactoryBean.setMapperLocations( new PathMatchingResourcePatternResolver().getResources( "classpath:mapper/*.xml" ) );
        } catch (IOException e) {
            logger.error( e.getLocalizedMessage() );
        }
        //分页工具
        Interceptor pageInterceptor = new PageHelper();
        Properties pageProperties = new Properties();
        pageProperties.setProperty( "reasonable" ,"true");
        pageInterceptor.setProperties( pageProperties );
        sqlSessionFactoryBean.setPlugins( new Interceptor[]{pageInterceptor} );
        return sqlSessionFactoryBean;
    }

    //sqlSessionTemplate
    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate( sqlSessionFactory );
        return sqlSessionTemplate;
    }

    //扫描 mybatis ***mapper接口
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setBasePackage( "com.dao" );
        mapperScannerConfigurer.setSqlSessionFactoryBeanName( "sqlSessionFactoryBean" );
        return mapperScannerConfigurer;
    }

    @Bean
    public userMapper userMapper(SqlSessionTemplate sqlSessionTemplate){
        userMapper mapper = sqlSessionTemplate.getMapper( userMapper.class );
        return mapper;
    }

    //========================声明式事务配置=========================
    //事务管理器（声明式的事务）
    @Bean
    public DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource) {
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource( dataSource );
        return dataSourceTransactionManager;
    }

    //事务管理   使用拦截器
    @Bean
    public TransactionInterceptor transactionInterceptor(DataSourceTransactionManager dataSourceTransactionManager) {
        TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
        transactionInterceptor.setTransactionManager( dataSourceTransactionManager );
        Properties properties = new Properties();
        properties.setProperty( "*", "readOnly" );
        properties.setProperty( "add*", "PROPAGATION_REQUIRED,-Exception" );
        properties.setProperty( "save*", "PROPAGATION_REQUIRED,-Exception" );
        properties.setProperty( "insert*", "PROPAGATION_REQUIRED,-Exception" );
        properties.setProperty( "modify*", "PROPAGATION_REQUIRED,-Exception" );
        properties.setProperty( "update*", "PROPAGATION_REQUIRED,-Exception" );
        properties.setProperty( "delete*", "PROPAGATION_REQUIRED,-Exception" );
        properties.setProperty( "remove*", "PROPAGATION_REQUIRED,-Exception" );
        properties.setProperty( "query*", "PROPAGATION_REQUIRED,-Exception" );
        properties.setProperty( "select*", "PROPAGATION_REQUIRED,-Exception" );
        properties.setProperty( "load*", "PROPAGATION_REQUIRED,-Exception" );
        transactionInterceptor.setTransactionAttributes( properties );
        return transactionInterceptor;
    }

    //创建proxy
    @Bean
    public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
        BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
        beanNameAutoProxyCreator.setBeanNames( "*Mapper" );//定义为哪些bena生成代理
        beanNameAutoProxyCreator.setInterceptorNames( "transactionInterceptor" );//设置拦截器的名称（可设置多个）
        return beanNameAutoProxyCreator;
    }


    //==========================缓存配置=======================

    //这个简单的缓存管理器使用java.util.concurrent.ConcurrentHashMap作
    //为其缓存存储。它非常简单，因此对于开发、测试或基础的应用来讲，这是一个很不错的选择
    @Profile({"dev", "default"})
    @Bean
    public ConcurrentMapCacheManager concurrentMapCacheManager() {

        ConcurrentMapCacheManager concurrentMapCacheManager = new ConcurrentMapCacheManager();
        HashSet<String> cacheNames = new HashSet<>();
        cacheNames.add( "User" );
        concurrentMapCacheManager.setCacheNames( cacheNames);
        return concurrentMapCacheManager;
    }

    @Profile({"dev", "default"})
    @Bean
    public ConcurrentMapCacheFactoryBean concurrentMapCacheFactoryBean(){
        ConcurrentMapCacheFactoryBean concurrentMapCacheFactoryBean = new ConcurrentMapCacheFactoryBean();
        concurrentMapCacheFactoryBean.setName( "User" );
        return concurrentMapCacheFactoryBean;
    }

    @Profile({"dev", "default"})
    @Bean
    public Cache cache(){
        ConcurrentMapCache concurrentMapCache = new ConcurrentMapCache( "User" ,false);
        return concurrentMapCache;
    }


    @Bean
    public JedisPoolConfig jedisPoolConfig() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle( environment.getProperty( "redis.maxIdle", Integer.class ) );
        jedisPoolConfig.setMaxWaitMillis( environment.getProperty( "redis.maxWait", Integer.class ) );
        jedisPoolConfig.setMaxTotal( environment.getProperty( "redis.maxTotal", Integer.class ) );
        jedisPoolConfig.setTestOnBorrow( environment.getProperty( "redis.testOnBorrow", Boolean.class ) );
        return jedisPoolConfig;
    }

    @Bean
    public JedisConnectionFactory jedisConnectionFactory(JedisPoolConfig jedisPoolConfig) {
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
        jedisConnectionFactory.setPoolConfig( jedisPoolConfig );
        jedisConnectionFactory.setHostName( environment.getProperty( "redis.host" ) );
        jedisConnectionFactory.setPort( environment.getProperty( "redis.port", Integer.class ) );
        jedisConnectionFactory.setDatabase( environment.getProperty( "redis.dbIndex", Integer.class ) );
        if (StringUtils.isNoneBlank( environment.getProperty( "redis.password" ) )) {
            jedisConnectionFactory.setPassword( environment.getProperty( "redis.password", "" ) );
        }
        jedisConnectionFactory.afterPropertiesSet();
        return jedisConnectionFactory;
    }

    @Profile("pro")
    @Bean
    public CacheManager cacheManager(RedisTemplate redisTemplate) {
        RedisCacheManager cacheManager = new RedisCacheManager( redisTemplate );
        return cacheManager;
    }

    @Bean
    public RedisTemplate redisTemplate(JedisConnectionFactory jedisConnectionFactory) {
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory( jedisConnectionFactory );
        redisTemplate.setKeySerializer( new StringRedisSerializer() );
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }




    //=======================================web 工具==============================
    //    restTemplate
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }
}
